import { cleanup, effect } from '../effect/effect.js';

/**
 * 监听源数据的变化，并在数据变化时调用回调函数
 * @param { Function | Object } source 监听的源数据，支持函数或响应式对象
 * @param {*} callback 数据变化时调用的回调函数
 * @param {*} options 选项对象，包含 immediate 和 deep 等配置
 */
export const watch = (source, callback, options = {}) => {
  let getter; // getter 函数可以只监听响应式对象的某个属性
  // 参数归一化处理
  if (typeof source === 'function') {
    getter = source; // 如果源数据是函数，直接赋值给 getter
  } else {
    getter = () => traverse(source); // 如果源数据不是函数，递归遍历产生新的响应式对象并返回
  }
  let oldVal, newVal;
  // 是否立即执行
  const { immediate } = options;
  /**
   * 工作函数，用于在数据变化时调用回调函数
   */
  const workFn = () => {
    newVal = effectFn(); // 即 environment 函数 -> 传入的 getter() -> 新值
    callback(newVal, oldVal);
    oldVal = newVal;
  };
  const effectFn = effect(() => getter(), {
    lazy: true,
    scheduler: () => {
      if (options.flush === 'post') {
        Promise.resolve().then(workFn);
      } else {
        workFn();
      }
    },
  });
  if (immediate) {
    workFn();
  } else {
    effectFn();
  }
  return () => cleanup(effectFn);
};

/**
 * 递归遍历目标对象，将所有属性转换为响应式对象
 * @param {*} target 目标对象
 * @param {Set} seen 已遍历过的对象集合，用于避免循环引用
 * @returns 遍历后的目标对象
 */
function traverse(target, seen = new Set()) {
  if (typeof target !== 'object' || target === null || seen.has(target)) {
    return target;
  }
  seen.add(target);
  for (const key in target) {
    traverse(target[key], seen);
  }
  return target; // 返回遍历后的目标对象
}
